﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Vibz.TeamAssignment.Common;
using Vibz.TeamAssignment.Common.Entity;
using Vibz.SharePoint;
using System.Xml.Linq;
using Vibz.SharePoint.Query;
using System.Windows.Forms;
using Extensil.Common;

namespace Vibz.TeamAssignment.Sharepoint
{
    public class AssignmentManager : IAssignmentManager
    {
        string siteUrl;
        SPWeb SPWeb;
        SPList SPList;
        SPSiteData SiteData;
        List<TaskGroup> _customTaskGroup;
        List<TaskGroup> AllTaskGroup
        {
            get
            {
                TaskGroup[] list = new TaskGroup[SPList.TaskGroup.Count];
                SPList.TaskGroup.CopyTo(list);
                List<TaskGroup> retValue = list.ToList();
                retValue.AddRange(_customTaskGroup);
                return retValue;
            }
        }
        public void Connect()
        {
            siteUrl = System.Configuration.ConfigurationManager.AppSettings["SPSite"];
            Connect(siteUrl);
        }
        public void Connect(string siteUrl)
        {
            if(string.IsNullOrEmpty(siteUrl))
                throw new ParameterNotDefinedException("SP Site");

            if(!SPSiteData.IsValidSite(siteUrl))
                throw new Exception("Configured SP site is not a valid TA site or might be corrupted.");

            SPWeb = new SPWeb(siteUrl);
            SiteData = new SPSiteData(siteUrl);
            SPList = new SPList(SPWeb, SiteData);
            
            if(!IsValidTASite())
                throw new Exception("Could not establish connection with configured TA site. This could be due to one of the following reason.\r\n\t[*] Network is down or not connected.\r\n\t[*] Configured SP site is not a valid TA site or corrupted. \r\n\t[*] Some of the required component is missing from the given site. \r\nPlease contact youe administrator for more help.");
        }
        bool IsValidTASite()
        {
            string[] lists = SiteData.GetAllList();
            bool missingList = false;
            foreach(string list in new string[] { 
                "Task", "TaskAssignment", "TaskGroup", "TaskGroupOwner", "TeamMember", "TaskMaster" })
            {
                if(!lists.Contains(list))
                {
                    missingList = true;
                    break;
                }
            }
            return !missingList;
        }
        Dictionary<string, object> CreateTaskParameter(Task task)
        {
            Dictionary<string, object> colValList = new Dictionary<string, object>();
            if(task.TaskID != -1)
                colValList.Add("ID", task.TaskID);
            colValList.Add("ParentID", task.ParentID);
            colValList.Add("TaskDescription", task.TaskDescription);
            colValList.Add("Author", GetUser(task.CreatedBy));
            colValList.Add("DueDate", task.DueDate);
            colValList.Add("EstimatedDuration", task.EstimatedDuration);
            colValList.Add("Title", task.Title);
            colValList.Add("GroupId", task.GroupID);
            colValList.Add("TaskStatus", task.Status);
            colValList.Add("CreatedBy", task.CreatedBy);
            return colValList;
        }
        public int CreateTask(Task task)
        {
            SPListCache.Expire("Task");
            SPListCache.Expire("ActiveTasks");
            return SPWeb.AddListItem("Task", CreateTaskParameter(task));
        }
        public int UpdateTask(Task task)
        {
            SPListCache.Expire("Task");
            SPListCache.Expire("ActiveTasks");
            return SPWeb.UpdateListItem("Task", CreateTaskParameter(task));
        }

        Dictionary<string, object> CreateTaskAssignmentParameter(TaskAssignment assignment)
        {
            Dictionary<string, object> colValList = new Dictionary<string, object>();
            if(assignment.ID != -1)
                colValList.Add("ID", assignment.ID);
            colValList.Add("TaskID", assignment.TaskID);
            colValList.Add("AssignedTo", assignment.AssignedTo);
            colValList.Add("AssignComment", assignment.AssignComment);
            colValList.Add("AssignBy", assignment.AssignBy);
            colValList.Add("IsRequest", assignment.IsRequest);
            colValList.Add("AssignRequestDate", assignment.AssignRequestDate);
            colValList.Add("AssignStatus", assignment.AssignStatus);
            return colValList;
        }
        public int CreateAssignment(TaskAssignment assignment)
        {
            SPListCache.Expire("TaskAssignment");
            SPListCache.Expire("ActiveAssignments");
            return SPWeb.AddListItem("TaskAssignment", CreateTaskAssignmentParameter(assignment));
        }
        public int UpdateAssignment(TaskAssignment assignment)
        {
            SPListCache.Expire("TaskAssignment");
            SPListCache.Expire("ActiveAssignments");
            return SPWeb.UpdateListItem("TaskAssignment", CreateTaskAssignmentParameter(assignment));
        }
        public List<string> GetAssignStatusList()
        {
            return SPList.AssignStatusList;
        }

        public Task GetTask(int taskID)
        {
            return SPList.GetTask(taskID);
        }
        public Task GetTask(string taskName)
        {
            return SPList.GetTask(taskName);
        }

        public List<TaskView> GetUsersTask(string userId)
        {
            var latestAssignments = SPList.ActiveAssignments
                .GroupBy(r => r.TaskID)
                .SelectMany(g => g.Where(r => r.AssignRequestDate == g.Max(a => a.AssignRequestDate)))
                .Where(a => a.AssignStatus != AssignStatus.Closed)
                .ToList();

            var latestAssignmentsByUser = SPList.ActiveAssignments
                .Where(a => a.AssignBy == userId 
                    && a.AssignStatus != AssignStatus.Rejected)
                .GroupBy(r => r.TaskID)
                .SelectMany(g => g.Where(r => r.AssignRequestDate == g.Max(a => a.AssignRequestDate)))
                .Where(a => a.AssignStatus != AssignStatus.Closed)
                .ToList();

            var assignTo = from lAss in latestAssignments
                          join tAss in SPList.ActiveAssignments on lAss.ID equals tAss.ID
                          join task in SPList.ActiveTasks on tAss.TaskID equals task.TaskID
                          join tGroup in AllTaskGroup on task.GroupID equals tGroup.ID
                          where tAss.AssignedTo == userId
                          orderby task.DueDate
                          select new TaskView(task, tGroup, tAss);

            var assignBy = from lAss in latestAssignmentsByUser
                           join tAss in SPList.ActiveAssignments on lAss.ID equals tAss.ID
                           join task in SPList.ActiveTasks on tAss.TaskID equals task.TaskID
                           join tGroup in AllTaskGroup on task.GroupID equals tGroup.ID
                           where tAss.AssignBy == userId
                           orderby task.DueDate
                           select new TaskView(task, tGroup, tAss);

            return assignTo.ToList().Union(assignBy.ToList()).DistinctBy(a => a.Task.TaskID).OrderBy(tv => tv.Task.DueDate).ToList();
        }
        public List<TaskView> GetImmediateSubTask(int taskId)
        {
            if(taskId == -1)
                return null;
            
            List<Task> taskList = SPList.GetTask(
                 Expression.Create("ParentID", taskId.ToString(), Operator.Eq)
                );

            var taskAss = SPList.GetTaskAssignment(
                    Expression.Create("TaskID", taskId.ToString(), Operator.Eq));

            var maxDate = (from tAss2
                             in taskAss
                           where taskId == tAss2.TaskID
                           select tAss2).Select(t => t.AssignRequestDate).Max();

            var results =
                from task in taskList
                join tAss in taskAss on maxDate equals tAss.AssignRequestDate
                join tGroup in AllTaskGroup on task.GroupID equals tGroup.ID
                orderby task.DueDate
                select new TaskView(task, tGroup, tAss);

            return results.ToList();
        }
        public List<Task> GetAllSubTask(int taskId)
        {
            if(taskId == -1)
                return null;

            List<Task> taskList = SPList.GetTask(
                 Expression.Create("ParentID", taskId.ToString(), Operator.Eq)
                );

            int taskCount = taskList.Count;
            for(int i = 0; i < taskCount;i++)
            {
                Task task = taskList[i];
                taskList.AddRange(GetAllSubTask(task.TaskID));
            }
            return taskList;
        }

        public TaskAssignment GetLatestAssignment(int taskID)
        {
            return SPList.GetLatestAssignment(taskID);
        }
        public List<TaskAssignment> GetAllAssignments(int taskID)
        {
            return SPList.GetAllAssignments(taskID);
        }
        public List<TaskGroup> GetUsersTaskGroup(string userID)
        {
            var results =
                from grp in AllTaskGroup
                join gOwner in SPList.TaskGroupOwner on grp.ID equals gOwner.GroupId
                where gOwner.OwnerId.ToLower() == userID.ToLower()
                orderby grp.Title
                select grp;

            if(results == null)
                return new List<TaskGroup>();
            return results.ToList();
        }
        public List<TeamMember> GetAllTeamMember()
        {
            return SPList.TeamMember;
        }
        public List<TaskGroup> GetAllTaskGroup()
        {
            return SPList.TaskGroup;
        }
        public List<TaskGroupOwner> GetAllTaskGroupOwner()
        {
            return SPList.TaskGroupOwner;
        }
        public List<string> GetAllMembers()
        {
            return SPList.TeamMember.Select(member => member.MemberID).ToList();
        }
        public List<string> GetAsignee(string userID)
        {
            return SPList.GetTeamMember(
                  Expression.Create("ManagerID", userID, Operator.Eq)
                 ).Select(member => member.MemberID).ToList();
        }
        public List<string> GetNonAsignee(string userID)
        {
            return SPList.GetTeamMember(
                  Expression.Create("ManagerID", userID, Operator.Neq)
                 ).Select(member => member.MemberID).ToList();
        }
        public List<TaskMasterEntry> GetAllConfig()
        {
            return SPList.TaskMaster;
        }
        public string GetConfig(string key)
        {
            List<TaskMasterEntry> master = SPList.TaskMaster.Where(entry => entry.Key == key).ToList();
            if(master != null && master.Count != 0)
                return master[0].Value;
            return "";
        }
        public string GetGroupName(int groupId)
        {
            List<TaskGroup> groupList = AllTaskGroup.Where(group => group.ID == groupId).ToList();
            if(groupList != null && groupList.Count != 0)
                return groupList[0].Title;
            return "";
        }
        public bool IsUserAdmin(string userCred)
        {
            return SPWeb.UserGroup.IsUserAdmin(userCred);
        }
        internal static string GetUser(string fullName)
        {
            int stop = fullName.IndexOf("\\");
            return (stop > -1) ? fullName.Substring(stop + 1, fullName.Length - stop - 1).ToLower() : null;
        }
        public int QueryInterval
        {
            get
            {
                return SPList.QueryInterval;
            }
        }
        public Form GetSettingForm(BaseCategory category)
        {
            return new SharePointSettings(category);
        }
        public void AddCustomTaskGroup(int id, string name)
        {
            if(_customTaskGroup == null)
                _customTaskGroup = new List<TaskGroup>();
            if(_customTaskGroup.Where(tg => tg.ID == id).Count() == 0)
                _customTaskGroup.Add(new TaskGroup(id, name));
        }
        public int AddTeamMember(string userId, string managerId)
        {
            SPListCache.Expire("TeamMember");

            Dictionary<string, object> param = new Dictionary<string, object>();
            param.Add("MemberID", userId);
            param.Add("ManagerID", managerId);
            return SPWeb.AddOrUpdateListItem("TeamMember", param, "MemberID");
        }
        public int UpdateTaskMaster(string key, string value)
        {
            SPListCache.Expire("TaskMaster");

            Dictionary<string, object> param = new Dictionary<string, object>();
            param.Add("Key", key);
            param.Add("Value", value);
            return SPWeb.AddOrUpdateListItem("TaskMaster", param, "Key");
        }
        public int AddTaskGroup(string title)
        {
            SPListCache.Expire("TaskGroup");
            SPListCache.Expire("TaskGroupOwner");

            Dictionary<string, object> colValList = new Dictionary<string, object>();
            colValList.Add("Title", title);
            return SPWeb.AddListItem("TaskGroup", colValList, "ID");
        }
        public int AddTaskGroupOwner(int groupId, string userId)
        {
            Dictionary<string, object> param = new Dictionary<string, object>();
            param.Add("GroupId", groupId);
            param.Add("OwnerId", userId);
            return SPWeb.AddListItem("TaskGroupOwner", param);
        }
        public int DeleteTaskGroupOwner(int groupId, string userId)
        {
            Dictionary<string, object> param = new Dictionary<string, object>();
            param.Add("GroupId", groupId);
            param.Add("OwnerId", userId);
            return SPWeb.DeleteListItem("TaskGroupOwner", param);
        }
        public void ClearCache()
        {
            SPListCache.Clear();
        }
    }
}
